﻿//
// Created by Grishul Eugeny, Shakola Igor
//
// See license in License.txt
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NCommander.Core;
using System.ServiceProcess;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;

namespace NCommander.NodeProviders
{
	[ShortName( "services" )]
	internal sealed class ServiceProvider : NodeProvider
	{
		internal class ServiceNode : Node
		{
			public ServiceController Controller;

			public override string Path
			{
				get { return Controller.ServiceName; }
			}

			public override Node Parent { get { return null; } }
			public override NodeType Type { get { return NodeType.External; } }

			private string _imagePath;
			public string ImagePath
			{
				get
				{
					try
					{
						return _imagePath = _imagePath ?? Win32.QueryServiceConfig( Controller.ServiceHandle.DangerousGetHandle() ).lpBinaryPathName;
					}
					catch( Exception excpt ) { return excpt.Message; }
				}
			}

			private string _logOnAs;
			public string LogOnAs
			{
				get
				{
					try
					{
						return _logOnAs = _logOnAs ?? Win32.QueryServiceConfig( Controller.ServiceHandle.DangerousGetHandle() ).lpServiceStartName;
					}
					catch( Exception excpt ) { return excpt.Message; }
				}
			}

			public enum ServiceStartupType
			{
				AutoStart = 2,
				BootStart = 0,
				DemandStart = 3,
				Disabled = 4,
				SystemStart = 1,

				Invalid = 0x7FFFFFFF
			}

			private ServiceStartupType? _startupType;
			public ServiceStartupType StartupType
			{
				get
				{
					try
					{
						return ( _startupType = _startupType ?? ( ServiceStartupType ) Win32.QueryServiceConfig( Controller.ServiceHandle.DangerousGetHandle() ).dwStartType ).Value;
					}
					catch( Exception ) { return ServiceStartupType.Invalid; }
				}
			}
		}

		public override Node[] Roots
		{
			get { return null; }
		}

		public override Node CurrentNode
		{
			get { return null; }
			set { throw new ArgumentException( "Can not change current node!", "value" ); }
		}

		public override Node GetNode( string path )
		{
			throw new NotImplementedException();
		}

		public override IEnumerable<Node> GetNodes()
		{
			return ServiceController.GetServices().Select( x => ( Node ) new ServiceNode() { Controller = x } );
		}

		public IEnumerable<Node> GetDrivers()
		{
			return ServiceController.GetDevices().Select( x => ( Node ) new ServiceNode() { Controller = x } );
		}

		public override void CreateTextRepresentation( StreamWriter writer )
		{
			foreach( var node in GetNodes().Cast<ServiceNode>().OrderBy( x => x.Controller.ServiceName ) )
			{
				writer.WriteLine( node.Controller.ServiceName );

				writer.WriteLine( "\tDisplay name: {0}", node.Controller.DisplayName );
				writer.WriteLine( "\tStatus: {0}", node.Controller.Status );
				writer.WriteLine( "\tImage: {0}", node.ImagePath );
				writer.WriteLine( "\tLog on as: {0}", node.LogOnAs );
				writer.WriteLine( "\tDependencies: {0}", string.Join( ", ", node.Controller.DependentServices.Select( x => x.ServiceName ).ToArray() ) );
			}
		}

		public override void OnDelete( Node[] nodes )
		{
			List<ServiceNode> removed = new List<ServiceNode>();

			foreach( ServiceNode item in nodes )
			{
				if( !Win32.DeleteService( item.Controller.ServiceHandle.DangerousGetHandle() ) )
					removed.Add( item );

				item.Controller.Close();
			}

			InvokeRefresh( new RefreshEventArgs() { Removed = removed.ToArray() } );

			if( removed.Count > 0 )
				throw new Exception( "Can not remove following services: " + string.Join( ", ", removed.Select( x => x.Controller.ServiceName ).ToArray() ) );
		}

		public override void OnExecute( Node node )
		{
			Process.Start( "mmc.exe", "services.msc" ).WaitForInputIdle();
			Thread.Sleep( 600 );

			SendKeys.Send( "\t" + ( node as ServiceNode ).Controller.DisplayName + "\n" );
		}
	}
}
